package com.yyfax.pay.quartz.dynamic;

import java.lang.reflect.Field;

import javax.annotation.Resource;

import org.quartz.SchedulerContext;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import org.springframework.util.ReflectionUtils;

public class QuartzJobFactory extends SpringBeanJobFactory {

	@Resource
	private AutowireCapableBeanFactory beanFactory;

	/**
	 * 这里覆盖了super的createJobInstance方法，从spring factory中获取bean。
	 */
	@Override
	protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {

		Object job = beanFactory.resolveNamedBean(bundle.getJobDetail().getJobClass()).getBeanInstance();

		Field schedulerContextField = this.getClass().getSuperclass().getDeclaredField("schedulerContext");
		schedulerContextField.setAccessible(true);
		SchedulerContext schedulerContext = (SchedulerContext) ReflectionUtils.getField(schedulerContextField, this);

		Field ignoredUnknownPropertiesField = this.getClass().getSuperclass().getDeclaredField("ignoredUnknownProperties");
		ignoredUnknownPropertiesField.setAccessible(true);
		String[] ignoredUnknownProperties = (String[]) ReflectionUtils.getField(ignoredUnknownPropertiesField, this);

		if (isEligibleForPropertyPopulation(job)) {
			BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(job);
			MutablePropertyValues pvs = new MutablePropertyValues();
			if (schedulerContext != null) {
				pvs.addPropertyValues(schedulerContext);
			}
			pvs.addPropertyValues(bundle.getJobDetail().getJobDataMap());
			pvs.addPropertyValues(bundle.getTrigger().getJobDataMap());
			if (ignoredUnknownProperties != null) {
				for (String propName : ignoredUnknownProperties) {
					if (pvs.contains(propName) && !bw.isWritableProperty(propName)) {
						pvs.removePropertyValue(propName);
					}
				}
				bw.setPropertyValues(pvs);
			} else {
				bw.setPropertyValues(pvs, true);
			}
		}

		return job;

	}
}
